package com.wondertek.onvif.service;

import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.regex.Pattern;
import java.util.regex.Matcher;

/**
 * ONVIF设备发现服务
 * 实现WS-Discovery协议进行局域网设备发现
 * 
 * @author wondertek
 * @version 1.0.0
 */
@Slf4j
@Service
public class OnvifDiscoveryService {

    private static final Logger log = LoggerFactory.getLogger(OnvifDiscoveryService.class);
    
    // WS-Discovery相关常量
    @Value("${onvif.discovery.multicast-address:239.255.255.250}")
    private String MULTICAST_ADDRESS;
    
    @Value("${onvif.discovery.multicast-address-ipv6:ff02::c}")
    private String MULTICAST_ADDRESS_IPV6;
    
    @Value("${onvif.discovery.multicast-port:3702}")
    private int MULTICAST_PORT;
    
    @Value("${onvif.discovery.timeout:10}")
    private int discoveryTimeoutSeconds;
    
    // IPv6发现可能需要更长的超时时间
    @Value("${onvif.discovery.ipv6-timeout:15}")
    private int ipv6DiscoveryTimeoutSeconds;
    
    @Value("${onvif.connection.retry-count:3}")
    private int MAX_RETRY_COUNT;
    
    @Value("${onvif.discovery.enable-ipv6:true}")
    private boolean enableIPv6;
    
    private static final int TTL = 4;
    
    // 计算的超时时间（毫秒）
    private int getDiscoveryTimeout() {
        return discoveryTimeoutSeconds * 1000;
    }
    
    // 计算IPv6发现的超时时间（毫秒）
    private int getIPv6DiscoveryTimeout() {
        return ipv6DiscoveryTimeoutSeconds * 1000;
    }
    
    // 计算总的发现超时时间，确保IPv6设备有足够时间响应
    private int getTotalDiscoveryTimeout() {
        return Math.max(getDiscoveryTimeout(), getIPv6DiscoveryTimeout());
    }
    
    private final Map<String, DiscoveredDevice> discoveredDevices = new ConcurrentHashMap<>();

    /**
     * WS-Discovery Probe消息模板
     * 改进版本，移除Types限制以支持更多设备类型，包括不完全兼容ONVIF标准的NVR设备
     */
    private static final String PROBE_MESSAGE = 
        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
        "<soap:Envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\" " +
        "xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\" " +
        "xmlns:wsd=\"http://schemas.xmlsoap.org/ws/2005/04/discovery\" " +
        "xmlns:wsdp=\"http://schemas.xmlsoap.org/ws/2006/02/devprof\" " +
        "xmlns:tds=\"http://www.onvif.org/ver10/device/wsdl\" " +
        "xmlns:tns=\"http://www.onvif.org/ver10/network/wsdl\">" +
        "<soap:Header>" +
        "<wsa:Action>http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe</wsa:Action>" +
        "<wsa:MessageID>urn:uuid:%s</wsa:MessageID>" +
        "<wsa:ReplyTo><wsa:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:Address></wsa:ReplyTo>" +
        "<wsa:To>urn:schemas-xmlsoap-org:ws:2005:04:discovery</wsa:To>" +
        "</soap:Header>" +
        "<soap:Body>" +
        "<wsd:Probe>" +
        "</wsd:Probe>" +
        "</soap:Body>" +
        "</soap:Envelope>";

    /**
     * 发现局域网中的ONVIF设备
     * 
     * @return 发现的设备列表
     */
    public List<DiscoveredDevice> discoverDevices() {
        log.info("开始发现ONVIF设备...");
        discoveredDevices.clear();
        
        return discoverDevicesWithRetry(0);
    }
    
    /**
     * 带重试机制的设备发现
     * 改进版本：增加重试逻辑，提高发现成功率，支持IPv4和IPv6分离发现
     * 
     * @param retryCount 当前重试次数
     * @return 发现的设备列表
     */
    private List<DiscoveredDevice> discoverDevicesWithRetry(int retryCount) {
        log.info("开始发现ONVIF设备...（第 {} 次尝试）", retryCount + 1);
        
        try {
            // 获取本机所有网络接口
            List<NetworkInterface> interfaces = getActiveNetworkInterfaces();
            
            // 分别启动IPv4和IPv6发现任务
            List<CompletableFuture<Void>> futures = new ArrayList<>();
            
            // IPv4发现任务
            for (NetworkInterface networkInterface : interfaces) {
                CompletableFuture<Void> ipv4Future = CompletableFuture.runAsync(() -> 
                    discoverOnInterfaceIPv4(networkInterface));
                futures.add(ipv4Future);
            }
            
            // IPv6发现任务（仅在启用时）
            if (enableIPv6) {
                log.info("IPv6设备发现已启用，开始IPv6发现...");
                for (NetworkInterface networkInterface : interfaces) {
                    CompletableFuture<Void> ipv6Future = CompletableFuture.runAsync(() -> 
                        discoverOnInterfaceIPv6(networkInterface));
                    futures.add(ipv6Future);
                }
            } else {
                log.info("IPv6设备发现已禁用，仅进行IPv4发现");
            }
            
            // 等待所有发现任务完成或超时
            try {
                int totalTimeout = enableIPv6 ? getTotalDiscoveryTimeout() : getDiscoveryTimeout();
                CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
                    .orTimeout(totalTimeout, TimeUnit.MILLISECONDS)
                    .join();
                    
                // 额外等待一段时间，确保所有延迟的响应都能被处理
                Thread.sleep(1000);
                
            } catch (Exception e) {
                if (e.getCause() instanceof TimeoutException) {
                    log.warn("设备发现超时，已发现 {} 个设备", discoveredDevices.size());
                    
                    // 等待一段时间让延迟的响应有机会被处理
                    try {
                        Thread.sleep(2000);
                        log.info("等待延迟响应后，当前发现设备数量: {}", discoveredDevices.size());
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                    }
                    
                    // 如果还有重试次数且发现的设备较少，则进行重试
                    if (retryCount < MAX_RETRY_COUNT && discoveredDevices.size() < 2) {
                        log.info("开始第 {} 次重试设备发现...", retryCount + 1);
                        // 重试时不清空已发现的设备，而是继续累积
                        return discoverDevicesWithRetry(retryCount + 1);
                    }
                } else {
                    log.error("设备发现过程中发生错误", e);
                }
            }
                
        } catch (Exception e) {
            log.error("设备发现过程中发生错误", e);
            
            // 如果还有重试次数，则进行重试
            if (retryCount < MAX_RETRY_COUNT) {
                log.info("发生错误，开始第 {} 次重试设备发现...", retryCount + 1);
                // 重试时不清空已发现的设备，而是继续累积
                return discoverDevicesWithRetry(retryCount + 1);
            }
        }
        
        List<DiscoveredDevice> devices = new ArrayList<>(discoveredDevices.values());
        log.info("设备发现完成，共发现 {} 个设备，重试次数: {}，IPv6发现: {}", 
            devices.size(), retryCount, enableIPv6 ? "启用" : "禁用");
        return devices;
    }


    
    /**
     * 在指定网络接口上进行IPv4设备发现
     * 改进版本：添加接口地址检查，仅在有IPv4地址的接口上进行发现
     * 
     * @param networkInterface 网络接口
     */
    private void discoverOnInterfaceIPv4(NetworkInterface networkInterface) {
        String interfaceName = networkInterface.getName();
        
        // 检查接口是否有IPv4地址
        boolean hasIPv4 = false;
        Enumeration<InetAddress> addresses = networkInterface.getInetAddresses();
        while (addresses.hasMoreElements()) {
            InetAddress addr = addresses.nextElement();
            if (addr instanceof Inet4Address && !addr.isLoopbackAddress()) {
                log.info("接口 {} 的IPv4地址: {}，开始IPv4设备发现", interfaceName, addr.getHostAddress());
                hasIPv4 = true;
                break;
            }
        }
        
        if (!hasIPv4) {
            log.debug("接口 {} 没有可用的IPv4地址，跳过IPv4发现", interfaceName);
            return;
        }
        MulticastSocket socket = null;
        try {
            log.debug("开始在网络接口 {} 上进行IPv4发现", interfaceName);
            
            // 创建多播套接字
            socket = new MulticastSocket();
            socket.setNetworkInterface(networkInterface);
            socket.setSoTimeout(getDiscoveryTimeout()); // 使用IPv4超时时间
            
            // 设置TTL
            socket.setTimeToLive(TTL);
            log.debug("设置IPv4多播TTL为: {}", TTL);
            
            // 加入多播组
            InetAddress group = InetAddress.getByName(MULTICAST_ADDRESS);
            socket.joinGroup(group);
            log.debug("已加入IPv4多播组 {} 在接口 {}", MULTICAST_ADDRESS, interfaceName);
            
            // 发送Probe消息
            sendProbeMessage(socket, group);
            
            // 接收响应，使用IPv6专用超时时间
            receiveResponsesWithTimeout(socket, getIPv6DiscoveryTimeout());
            
            socket.leaveGroup(group);
            log.debug("已离开IPv4多播组 {} 在接口 {}", MULTICAST_ADDRESS, interfaceName);
            
        } catch (SocketTimeoutException e) {
            log.debug("网络接口 {} 上的设备发现超时，这是正常现象", networkInterface.getName());
        } catch (IOException e) {
            log.warn("在网络接口 {} 上发现设备时发生IO错误: {}", 
                networkInterface.getName(), e.getMessage());
            log.debug("IO错误详情", e);
        } catch (Exception e) {
            log.error("在网络接口 {} 上发现设备时发生错误", networkInterface.getName(), e);
        } finally {
            if (socket != null && !socket.isClosed()) {
                try {
                    socket.close();
                    log.debug("已关闭网络接口 {} 的IPv4套接字", networkInterface.getName());
                } catch (Exception e) {
                    log.debug("关闭IPv4套接字时发生错误: {}", e.getMessage());
                }
            }
        }
    }
    
    /**
     * 在指定网络接口上进行IPv6设备发现
     * 改进版本：添加启用状态检查和接口地址检查，仅在启用IPv6且有IPv6地址的接口上进行发现
     * 
     * @param networkInterface 网络接口
     */
    private void discoverOnInterfaceIPv6(NetworkInterface networkInterface) {
        String interfaceName = networkInterface.getName();
        
        // 检查IPv6是否启用
        if (!enableIPv6) {
            log.debug("IPv6设备发现已禁用，跳过接口 {} 的IPv6发现", interfaceName);
            return;
        }
        
        // 检查接口是否有IPv6地址
        boolean hasIPv6 = false;
        Enumeration<InetAddress> addresses = networkInterface.getInetAddresses();
        while (addresses.hasMoreElements()) {
            InetAddress addr = addresses.nextElement();
            if (addr instanceof Inet6Address && !addr.isLoopbackAddress()) {
                log.info("接口 {} 的IPv6地址: {}，开始IPv6设备发现", interfaceName, addr.getHostAddress());
                hasIPv6 = true;
                break;
            }
        }
        
        if (!hasIPv6) {
            log.debug("接口 {} 没有可用的IPv6地址，跳过IPv6发现", interfaceName);
            return;
        }
        
        MulticastSocket socket = null;
        try {
            log.debug("开始在网络接口 {} 上进行IPv6发现", interfaceName);
            
            // 创建多播套接字
            socket = new MulticastSocket();
            socket.setNetworkInterface(networkInterface);
            socket.setSoTimeout(getIPv6DiscoveryTimeout());
            
            // 设置TTL
            socket.setTimeToLive(TTL);
            log.debug("设置IPv6多播TTL为: {}", TTL);
            
            // 加入IPv6多播组
            InetAddress group = InetAddress.getByName(MULTICAST_ADDRESS_IPV6);
            socket.joinGroup(group);
            log.debug("已加入IPv6多播组 {} 在接口 {}", MULTICAST_ADDRESS_IPV6, interfaceName);
            
            // 发送Probe消息
            sendProbeMessage(socket, group);
            
            // 接收响应，使用IPv6超时时间
            receiveResponsesWithTimeout(socket, getIPv6DiscoveryTimeout());
            
            socket.leaveGroup(group);
            log.debug("已离开IPv6多播组 {} 在接口 {}", MULTICAST_ADDRESS_IPV6, interfaceName);
            
        } catch (SocketTimeoutException e) {
            log.debug("网络接口 {} 上的IPv6设备发现超时，这是正常现象", networkInterface.getName());
        } catch (IOException e) {
            log.warn("在网络接口 {} 上进行IPv6发现时发生IO错误: {}", 
                networkInterface.getName(), e.getMessage());
            log.debug("IPv6 IO错误详情", e);
        } catch (Exception e) {
            log.error("在网络接口 {} 上进行IPv6发现时发生错误", networkInterface.getName(), e);
        } finally {
            if (socket != null && !socket.isClosed()) {
                try {
                    socket.close();
                    log.debug("已关闭网络接口 {} 的IPv6套接字", networkInterface.getName());
                } catch (Exception e) {
                    log.debug("关闭IPv6套接字时发生错误: {}", e.getMessage());
                }
            }
        }
    }

    /**
     * 发送WS-Discovery Probe消息
     * 改进版本：添加详细的消息内容日志和错误处理
     * 
     * @param socket 多播套接字
     * @param group 多播组地址
     */
    private void sendProbeMessage(MulticastSocket socket, InetAddress group) throws IOException {
        String messageId = UUID.randomUUID().toString();
        String probeXml = String.format(PROBE_MESSAGE, messageId);
        
        log.debug("准备发送Probe消息，MessageID: {}", messageId);
        log.trace("Probe消息内容: {}", probeXml);
        
        byte[] data = probeXml.getBytes(StandardCharsets.UTF_8);
        DatagramPacket packet = new DatagramPacket(data, data.length, group, MULTICAST_PORT);
        
        log.info("发送Probe消息到 {}:{}, 数据长度: {} 字节", 
            group.getHostAddress(), MULTICAST_PORT, data.length);
        
        socket.send(packet);
        log.info("成功发送Probe消息，MessageID: {}", messageId);
    }

    /**
     * 接收设备响应
     * 改进版本：添加详细的响应统计和错误处理，支持自定义超时时间
     * 
     * @param socket 多播套接字
     * @param timeoutMs 超时时间（毫秒）
     */
    private void receiveResponsesWithTimeout(MulticastSocket socket, int timeoutMs) {
        byte[] buffer = new byte[8192];
        long startTime = System.currentTimeMillis();
        int responseCount = 0;
        
        log.info("开始接收响应，超时时间: {} 毫秒", timeoutMs);
        
        while (System.currentTimeMillis() - startTime < timeoutMs) {
            try {
                DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
                socket.receive(packet);
                responseCount++;
                
                String response = new String(packet.getData(), 0, packet.getLength(), StandardCharsets.UTF_8);
                log.debug("收到第 {} 个响应，来自: {}, 长度: {} 字节", 
                    responseCount, packet.getAddress().getHostAddress(), packet.getLength());
                log.trace("响应内容: {}", response);
                
                parseProbeResponse(response, packet.getAddress());
                
            } catch (SocketTimeoutException e) {
                // 超时是正常的，继续等待
                log.debug("接收响应超时，这是正常现象");
                break;
            } catch (IOException e) {
                log.warn("接收响应时发生IO错误: {}", e.getMessage());
                break;
            } catch (Exception e) {
                log.error("接收响应时发生未知错误", e);
                break;
            }
        }
        
        long elapsedTime = System.currentTimeMillis() - startTime;
        log.info("响应接收完成，总共收到 {} 个响应，耗时: {} 毫秒", responseCount, elapsedTime);
    }
    
    /**
     * 接收设备响应（保持向后兼容）
     * 
     * @param socket 多播套接字
     */
    private void receiveResponses(MulticastSocket socket) {
        receiveResponsesWithTimeout(socket, getDiscoveryTimeout());
    }

    /**
     * 解析Probe响应消息
     * 改进版本：使用更宽松的设备类型检查，支持更多ONVIF设备
     * 
     * @param response 响应XML
     * @param address 设备IP地址
     */
    private void parseProbeResponse(String response, InetAddress address) {
        String deviceAddress = address.getHostAddress();
        try {
            
            // 检查响应类型
            boolean isProbeMatches = response.contains("ProbeMatches");
            boolean isSoapFault = response.contains("soap:Fault") || response.contains("Fault");
            
            if (!isProbeMatches && !isSoapFault) {
                log.debug("来自 {} 的响应既不是ProbeMatches也不是SOAP Fault，跳过。完整响应内容: {}", deviceAddress, response);
                return;
            }
            
            // 如果是SOAP Fault，检查是否为MatchingRuleNotSupported错误（表明设备可能支持ONVIF但不支持特定的匹配规则）
            if (isSoapFault) {
                if (response.contains("MatchingRuleNotSupported") || response.contains("wsd:MatchingRuleNotSupported")) {
                    log.info("设备 {} 返回MatchingRuleNotSupported错误，可能是ONVIF设备但不支持指定的匹配规则，尝试作为潜在设备处理", deviceAddress);
                    // 创建一个基本的设备条目
                    createBasicDeviceFromFault(deviceAddress);
                }
                return;
            }
            
            // 更宽松的ONVIF设备类型检查，支持NVR设备和各种厂商设备
            boolean isOnvifDevice = response.contains("NetworkVideoTransmitter") ||
                                  response.contains("NetworkVideoRecorder") ||
                                  response.contains("tds:Device") ||
                                  response.contains("Device") ||
                                  response.contains("onvif") ||
                                  response.contains("ONVIF") ||
                                  response.contains("urn:schemas-xmlsoap-org:ws:2005:04:discovery") ||
                                  response.contains("http://www.onvif.org") ||
                                  response.contains("tdn:NetworkVideoDisplay") ||
                                  response.contains("ter:ReceiverService") ||
                                  response.contains("tev:EventService") ||
                                  response.contains("timg:ImagingService") ||
                                  response.contains("tptz:PTZService") ||
                                  response.contains("trt:MediaService");
            
            if (!isOnvifDevice) {
                log.warn("来自 {} 的响应不包含ONVIF设备标识，跳过。响应内容: {}", deviceAddress, response.length() > 500 ? response.substring(0, 500) + "..." : response);
                return;
            }
            
            log.info("检测到来自 {} 的潜在ONVIF设备响应，开始解析", deviceAddress);
            
            // 输出原始XML响应内容用于调试
            log.debug("设备 {} 原始XML响应内容: {}", deviceAddress, response);
            
            // 提取设备信息 - 使用灵活的标签匹配
            String endpointReference = extractValueFlexible(response, "EndpointReference");
            String types = extractValueFlexible(response, "Types");
            String scopes = extractValueFlexible(response, "Scopes");
            String xAddrs = extractValueFlexible(response, "XAddrs");
            
            log.debug("设备 {} 解析结果 - Types: {}, XAddrs: {}", deviceAddress, types, xAddrs);
            log.debug("设备 {} 原始Scopes内容: {}", deviceAddress, scopes);
            
            // 验证关键字段 - 放宽验证条件，只要有其中一个字段不为空即可
            if (StrUtil.isEmpty(types) && StrUtil.isEmpty(xAddrs)) {
                log.warn("设备 {} 缺少关键信息 - Types和XAddrs都为空，但仍尝试解析", deviceAddress);
                // 不直接返回，继续尝试解析，可能是特殊的NVR设备
            }
            
            // 如果启用了TRACE级别，记录每个scope的详细信息
            if (log.isTraceEnabled()) {
                logScopeDetails(scopes, deviceAddress);
            }
            
            // 解析设备详细信息
            String manufacturer = extractManufacturerFromScopes(scopes);
            String model = extractModelFromScopes(scopes);
            String location = extractScopeValue(scopes, "location");
            
            log.debug("设备 {} 解析的厂商信息: {}, 型号: {}, 位置: {}", deviceAddress, manufacturer, model, location);
            
            // 确定IP版本
            String ipVersion = (address instanceof Inet6Address) ? "IPv6" : "IPv4";
            
            // 确定设备类型
            String deviceType = determineDeviceType(types, scopes);
            
            // 从xAddrs中提取ONVIF端口
            Integer onvifPort = extractOnvifPortFromXAddrs(xAddrs);
            
            // 创建发现的设备对象
            DiscoveredDevice device = DiscoveredDevice.builder()
                .ipAddress(deviceAddress)
                .ipVersion(ipVersion)
                .deviceType(deviceType)
                .endpointReference(endpointReference)
                .types(types)
                .scopes(scopes)
                .xAddrs(xAddrs)
                .manufacturer(manufacturer)
                .model(model)
                .location(location)
                .discoveryTime(new Date())
                .onvifPort(onvifPort)
                .build();
            
            discoveredDevices.put(deviceAddress, device);
            log.info("发现ONVIF设备: {} [{}] - {} {}", deviceAddress, deviceType, manufacturer, model);
            
            // 验证设备是否成功添加
            if (discoveredDevices.containsKey(deviceAddress)) {
                log.info("设备 {} 已成功添加到发现列表，当前发现设备总数: {}", deviceAddress, discoveredDevices.size());
            } else {
                log.error("设备 {} 添加到发现列表失败！", deviceAddress);
            }
            
        } catch (Exception e) {
            log.error("解析设备 {} 响应时发生错误: {}", deviceAddress, e.getMessage(), e);
            log.debug("导致解析失败的响应内容: {}", response.length() > 1000 ? response.substring(0, 1000) + "..." : response);
        }
    }

    /**
     * 从XAddrs中提取ONVIF端口号
     * @param xAddrs XAddrs字符串
     * @return 端口号，如果无法提取则返回80
     */
    private Integer extractOnvifPortFromXAddrs(String xAddrs) {
        if (StrUtil.isEmpty(xAddrs)) {
            log.debug("XAddrs为空，使用默认端口80");
            return 80;
        }
        
        try {
            // 解析XAddrs中的端口信息
            // 格式通常为: http://192.168.1.100:8080/onvif/device_service
            java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("http://[^:]+:(\\d+)");
            java.util.regex.Matcher matcher = pattern.matcher(xAddrs);
            if (matcher.find()) {
                int port = Integer.parseInt(matcher.group(1));
                log.debug("从XAddrs中提取到端口: {}, XAddrs: {}", port, xAddrs);
                return port;
            } else {
                // 如果没有明确指定端口，检查是否为标准HTTP端口
                if (xAddrs.startsWith("http://") && !xAddrs.contains(":80/") && !xAddrs.matches(".*:\\d+.*")) {
                    log.debug("XAddrs未指定端口，使用默认HTTP端口80: {}", xAddrs);
                    return 80;
                }
            }
        } catch (Exception e) {
            log.warn("解析XAddrs端口失败: {}, 错误: {}", xAddrs, e.getMessage());
        }
        
        log.debug("无法从XAddrs中提取端口，使用默认端口80: {}", xAddrs);
        return 80;
    }

    /**
     * 根据设备类型和作用域确定设备类型
     * 
     * @param types 设备类型字符串
     * @param scopes 设备作用域字符串
     * @return 设备类型："Camera", "NVR", "Unknown"
     */
    private String determineDeviceType(String types, String scopes) {
        try {
            if (StrUtil.isEmpty(types)) {
                log.trace("设备类型为空，无法确定设备类型");
                return "Unknown";
            }
            
            String typesLower = types.toLowerCase();
            String scopesLower = scopes != null ? scopes.toLowerCase() : "";
            
            // 检查是否为NVR设备
            if (typesLower.contains("networkvideorecorder") || 
                typesLower.contains("nvr") ||
                scopesLower.contains("nvr") ||
                scopesLower.contains("recorder")) {
                log.debug("检测到NVR设备，Types: {}, Scopes: {}", types, scopes);
                return "NVR";
            }
            
            // 检查是否为摄像头设备
            if (typesLower.contains("networkvideotransmitter") ||
                typesLower.contains("camera") ||
                scopesLower.contains("camera") ||
                scopesLower.contains("ipcam")) {
                log.debug("检测到摄像头设备，Types: {}, Scopes: {}", types, scopes);
                return "Camera";
            }
            
            // 默认情况
            log.debug("无法确定具体设备类型，Types: {}, Scopes: {}", types, scopes);
            return "Unknown";
            
        } catch (Exception e) {
            log.warn("确定设备类型时发生错误: {}", e.getMessage());
            return "Unknown";
        }
    }

    /**
     * 灵活的XML值提取方法，支持不同的命名空间前缀
     * @param xml XML内容
     * @param tagName 标签名（不包含命名空间前缀）
     * @return 提取的值
     */
    private String extractValueFlexible(String xml, String tagName) {
        try {
            if (xml == null || xml.isEmpty()) {
                log.trace("XML为空，无法提取 {} 标签的值", tagName);
                return "";
            }
            
            // 使用正则表达式匹配任意命名空间前缀的标签
            String pattern = "<[^:]*:?" + tagName + "[^>]*>(.*?)</[^:]*:?" + tagName + ">";
            Pattern regex = Pattern.compile(pattern, Pattern.DOTALL | Pattern.CASE_INSENSITIVE);
            Matcher matcher = regex.matcher(xml);
            
            if (matcher.find()) {
                String value = matcher.group(1).trim();
                log.trace("成功提取标签 {} 的值: {}", tagName, value);
                return value;
            }
            
            log.trace("未找到标签: {}", tagName);
            return "";
            
        } catch (Exception e) {
            log.warn("提取XML标签值时发生错误，标签: {}, 错误: {}", tagName, e.getMessage());
            return "";
        }
    }
    
    /**
     * 从XML中提取指定标签的值
     * 改进版本：添加更好的错误处理和日志记录
     * 
     * @param xml XML字符串
     * @param startTag 开始标签
     * @param endTag 结束标签
     * @return 提取的值
     */
    private String extractValue(String xml, String startTag, String endTag) {
        try {
            if (xml == null || xml.isEmpty()) {
                log.trace("XML为空，无法提取 {} 标签的值", startTag);
                return "";
            }
            
            int start = xml.indexOf(startTag);
            if (start == -1) {
                log.trace("未找到开始标签: {}", startTag);
                return "";
            }
            
            start += startTag.length();
            int end = xml.indexOf(endTag, start);
            if (end == -1) {
                log.trace("未找到结束标签: {}", endTag);
                return "";
            }
            
            String value = xml.substring(start, end).trim();
            log.trace("成功提取标签 {} 的值: {}", startTag, value);
            return value;
            
        } catch (Exception e) {
            log.warn("提取XML标签值时发生错误，标签: {}, 错误: {}", startTag, e.getMessage());
            return "";
        }
    }

    /**
     * 从Scopes中提取厂商信息
     * 根据ONVIF标准，厂商信息通常在hardware scope中
     * 格式: onvif://www.onvif.org/hardware/[manufacturer-model]
     * 
     * @param scopes Scopes字符串
     * @return 厂商名称
     */
    private String extractManufacturerFromScopes(String scopes) {
        try {
            if (StrUtil.isEmpty(scopes)) {
                log.trace("Scopes为空，无法提取厂商信息");
                return "";
            }
            
            log.trace("从Scopes中提取厂商信息: {}", scopes);
            
            String[] scopeArray = scopes.split("\\s+");
            for (String scope : scopeArray) {
                // 查找hardware scope
                if (scope.contains("/hardware/")) {
                    // 提取hardware后面的值
                    int hardwareIndex = scope.indexOf("/hardware/");
                    if (hardwareIndex != -1) {
                        String hardwareValue = scope.substring(hardwareIndex + "/hardware/".length());
                        // 如果包含连字符，通常第一部分是厂商名
                        if (hardwareValue.contains("-")) {
                            String manufacturer = hardwareValue.split("-")[0];
                            log.trace("从hardware scope {} 中提取到厂商: {}", scope, manufacturer);
                            return manufacturer;
                        } else {
                            log.trace("从hardware scope {} 中提取到厂商: {}", scope, hardwareValue);
                            return hardwareValue;
                        }
                    }
                }
                
                // 备用方案：查找可能包含厂商信息的其他scope
                if (scope.toLowerCase().contains("manufacturer") || 
                    scope.toLowerCase().contains("vendor") ||
                    scope.toLowerCase().contains("brand")) {
                    int lastSlash = scope.lastIndexOf("/");
                    if (lastSlash != -1 && lastSlash < scope.length() - 1) {
                        String value = scope.substring(lastSlash + 1);
                        log.trace("从厂商相关scope {} 中提取到厂商: {}", scope, value);
                        return value;
                    }
                }
            }
            
            log.trace("未在Scopes中找到厂商信息");
            return "";
            
        } catch (Exception e) {
            log.warn("从Scopes中提取厂商信息时发生错误: {}", e.getMessage());
            return "";
        }
    }
    
    /**
     * 从Scopes中提取型号信息
     * 根据ONVIF标准，型号信息通常在name scope中
     * 格式: onvif://www.onvif.org/name/[model-name]
     * 
     * @param scopes Scopes字符串
     * @return 型号名称
     */
    private String extractModelFromScopes(String scopes) {
        try {
            if (StrUtil.isEmpty(scopes)) {
                log.trace("Scopes为空，无法提取型号信息");
                return "";
            }
            
            log.trace("从Scopes中提取型号信息: {}", scopes);
            
            String[] scopeArray = scopes.split("\\s+");
            for (String scope : scopeArray) {
                // 查找name scope
                if (scope.contains("/name/")) {
                    int nameIndex = scope.indexOf("/name/");
                    if (nameIndex != -1) {
                        String nameValue = scope.substring(nameIndex + "/name/".length());
                        log.trace("从name scope {} 中提取到型号: {}", scope, nameValue);
                        return nameValue;
                    }
                }
                
                // 备用方案：从hardware scope中提取型号（如果包含连字符）
                if (scope.contains("/hardware/")) {
                    int hardwareIndex = scope.indexOf("/hardware/");
                    if (hardwareIndex != -1) {
                        String hardwareValue = scope.substring(hardwareIndex + "/hardware/".length());
                        if (hardwareValue.contains("-") && hardwareValue.split("-").length > 1) {
                            String model = hardwareValue.substring(hardwareValue.indexOf("-") + 1);
                            log.trace("从hardware scope {} 中提取到型号: {}", scope, model);
                            return model;
                        }
                    }
                }
                
                // 备用方案：查找可能包含型号信息的其他scope
                if (scope.toLowerCase().contains("model") || 
                    scope.toLowerCase().contains("type")) {
                    int lastSlash = scope.lastIndexOf("/");
                    if (lastSlash != -1 && lastSlash < scope.length() - 1) {
                        String value = scope.substring(lastSlash + 1);
                        log.trace("从型号相关scope {} 中提取到型号: {}", scope, value);
                        return value;
                    }
                }
            }
            
            log.trace("未在Scopes中找到型号信息");
            return "";
            
        } catch (Exception e) {
            log.warn("从Scopes中提取型号信息时发生错误: {}", e.getMessage());
            return "";
        }
    }

    /**
     * 记录Scopes的详细信息用于调试
     * 
     * @param scopes Scopes字符串
     * @param deviceAddress 设备地址
     */
    private void logScopeDetails(String scopes, String deviceAddress) {
        if (StrUtil.isEmpty(scopes)) {
            log.trace("设备 {} 的Scopes为空", deviceAddress);
            return;
        }
        
        String[] scopeArray = scopes.split("\\s+");
        log.trace("设备 {} 共有 {} 个scope:", deviceAddress, scopeArray.length);
        
        for (int i = 0; i < scopeArray.length; i++) {
            String scope = scopeArray[i];
            log.trace("  Scope[{}]: {}", i + 1, scope);
            
            // 分析scope的结构
            if (scope.contains("/hardware/")) {
                log.trace("    -> 包含hardware信息");
            }
            if (scope.contains("/name/")) {
                log.trace("    -> 包含name信息");
            }
            if (scope.contains("/location/")) {
                log.trace("    -> 包含location信息");
            }
            if (scope.toLowerCase().contains("manufacturer") || 
                scope.toLowerCase().contains("vendor") ||
                scope.toLowerCase().contains("brand")) {
                log.trace("    -> 可能包含厂商信息");
            }
        }
    }
    
    /**
     * 从Scopes中提取指定类型的值
     * 改进版本：支持多种scope格式和更好的错误处理
     * 
     * @param scopes Scopes字符串
     * @param type 类型
     * @return 提取的值
     */
    private String extractScopeValue(String scopes, String type) {
        try {
            if (StrUtil.isEmpty(scopes)) {
                log.trace("Scopes为空，无法提取类型: {}", type);
                return "";
            }
            
            log.trace("从Scopes中提取类型 {}: {}", type, scopes);
            
            String[] scopeArray = scopes.split("\\s+");
            for (String scope : scopeArray) {
                // 支持多种scope格式
                if (scope.contains("/" + type + "/") || 
                    scope.contains("=" + type + "=") ||
                    scope.toLowerCase().contains(type.toLowerCase())) {
                    
                    // 尝试从URL路径中提取
                    int lastSlash = scope.lastIndexOf("/");
                    if (lastSlash != -1 && lastSlash < scope.length() - 1) {
                        String value = scope.substring(lastSlash + 1);
                        log.trace("从scope {} 中提取到类型 {} 的值: {}", scope, type, value);
                        return value;
                    }
                    
                    // 尝试从键值对中提取
                    int equalIndex = scope.indexOf("=");
                    if (equalIndex != -1 && equalIndex < scope.length() - 1) {
                        String value = scope.substring(equalIndex + 1);
                        log.trace("从scope {} 中提取到类型 {} 的值: {}", scope, type, value);
                        return value;
                    }
                }
            }
            
            log.trace("未在Scopes中找到类型: {}", type);
            return "";
            
        } catch (Exception e) {
            log.warn("从Scopes中提取值时发生错误，类型: {}, 错误: {}", type, e.getMessage());
            return "";
        }
    }

    /**
     * 获取活跃的网络接口列表
     * 改进版本：更严格的接口筛选和详细的日志记录
     * 
     * @return 网络接口列表
     */
    private List<NetworkInterface> getActiveNetworkInterfaces() {
        List<NetworkInterface> interfaces = new ArrayList<>();
        try {
            log.info("开始扫描网络接口...");
            Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
            
            while (networkInterfaces.hasMoreElements()) {
                NetworkInterface networkInterface = networkInterfaces.nextElement();
                String interfaceName = networkInterface.getName();
                String displayName = networkInterface.getDisplayName();
                
                log.debug("检查网络接口: {} - {}", interfaceName, displayName);
                
                // 更严格的接口筛选
                if (networkInterface.isLoopback()) {
                    log.debug("跳过回环接口: {}", interfaceName);
                    continue;
                }
                
                if (!networkInterface.isUp()) {
                    log.debug("跳过非活跃接口: {}", interfaceName);
                    continue;
                }
                
                if (!networkInterface.supportsMulticast()) {
                    log.debug("跳过不支持多播的接口: {}", interfaceName);
                    continue;
                }
                
                if (networkInterface.isVirtual()) {
                    log.debug("跳过虚拟接口: {}", interfaceName);
                    continue;
                }
                
                // 检查是否有有效的IPv4和IPv6地址
                boolean hasValidIPv4 = false;
                boolean hasValidIPv6 = false;
                List<String> ipv4Addresses = new ArrayList<>();
                List<String> ipv6Addresses = new ArrayList<>();
                
                Enumeration<InetAddress> addresses = networkInterface.getInetAddresses();
                while (addresses.hasMoreElements()) {
                    InetAddress address = addresses.nextElement();
                    if (address instanceof Inet4Address) {
                        String ip = address.getHostAddress();
                        ipv4Addresses.add(ip);
                        
                        // 更严格的地址检查
                        if (!address.isLoopbackAddress() && 
                            !address.isLinkLocalAddress() && 
                            !address.isMulticastAddress() &&
                            !address.isAnyLocalAddress()) {
                            hasValidIPv4 = true;
                        }
                    } else if (address instanceof Inet6Address && enableIPv6) {
                        String ip = address.getHostAddress();
                        ipv6Addresses.add(ip);
                        
                        // IPv6地址检查
                        if (!address.isLoopbackAddress() && 
                            !address.isLinkLocalAddress() && 
                            !address.isMulticastAddress() &&
                            !address.isAnyLocalAddress() &&
                            !((Inet6Address) address).isSiteLocalAddress()) {
                            hasValidIPv6 = true;
                        }
                    }
                }
                
                if (hasValidIPv4 || hasValidIPv6) {
                    interfaces.add(networkInterface);
                    List<String> addressInfo = new ArrayList<>();
                    if (!ipv4Addresses.isEmpty()) {
                        addressInfo.add("IPv4: " + String.join(", ", ipv4Addresses));
                    }
                    if (!ipv6Addresses.isEmpty()) {
                        addressInfo.add("IPv6: " + String.join(", ", ipv6Addresses));
                    }
                    log.info("使用网络接口: {} - {} ({})", 
                        interfaceName, displayName, String.join("; ", addressInfo));
                } else {
                    log.debug("接口 {} 没有有效的IP地址，跳过", interfaceName);
                }
            }
            
            log.info("共找到 {} 个可用的网络接口", interfaces.size());
            
        } catch (SocketException e) {
            log.error("获取网络接口时发生错误", e);
        }
        return interfaces;
    }

    /**
     * 发现的设备信息
     */
    public static class DiscoveredDevice {
        private String ipAddress;
        private String ipVersion; // "IPv4" 或 "IPv6"
        private String deviceType; // "Camera", "NVR", "Unknown"
        private String endpointReference;
        private String types;
        private String scopes;
        private String xAddrs;
        private String manufacturer;
        private String model;
        private String location;
        private Date discoveryTime;
        private Integer onvifPort; // ONVIF端口号

        // Builder模式
        public static Builder builder() {
            return new Builder();
        }

        public static class Builder {
            private DiscoveredDevice device = new DiscoveredDevice();

            public Builder ipAddress(String ipAddress) {
                device.ipAddress = ipAddress;
                return this;
            }

            public Builder ipVersion(String ipVersion) {
                device.ipVersion = ipVersion;
                return this;
            }

            public Builder deviceType(String deviceType) {
                device.deviceType = deviceType;
                return this;
            }

            public Builder endpointReference(String endpointReference) {
                device.endpointReference = endpointReference;
                return this;
            }

            public Builder types(String types) {
                device.types = types;
                return this;
            }

            public Builder scopes(String scopes) {
                device.scopes = scopes;
                return this;
            }

            public Builder xAddrs(String xAddrs) {
                device.xAddrs = xAddrs;
                return this;
            }

            public Builder manufacturer(String manufacturer) {
                device.manufacturer = manufacturer;
                return this;
            }

            public Builder model(String model) {
                device.model = model;
                return this;
            }

            public Builder location(String location) {
                device.location = location;
                return this;
            }

            public Builder discoveryTime(Date discoveryTime) {
                device.discoveryTime = discoveryTime;
                return this;
            }

            public Builder onvifPort(Integer onvifPort) {
                device.onvifPort = onvifPort;
                return this;
            }

            public DiscoveredDevice build() {
                return device;
            }
        }

        // Getters
        public String getIpAddress() { return ipAddress; }
        public String getIpVersion() { return ipVersion; }
        public String getDeviceType() { return deviceType; }
        public String getEndpointReference() { return endpointReference; }
        public String getTypes() { return types; }
        public String getScopes() { return scopes; }
        public String getXAddrs() { return xAddrs; }
        public String getManufacturer() { return manufacturer; }
        public String getModel() { return model; }
        public String getLocation() { return location; }
        public Date getDiscoveryTime() { return discoveryTime; }
        public Integer getOnvifPort() { return onvifPort; }
    }
    
    /**
     * 为返回SOAP Fault的设备创建基本设备条目
     * 这些设备可能支持ONVIF但不支持特定的匹配规则
     */
    private void createBasicDeviceFromFault(String deviceAddress) {
        try {
            DiscoveredDevice device = new DiscoveredDevice.Builder()
                .ipAddress(deviceAddress)
                .ipVersion("IPv4")
                .deviceType("潜在ONVIF设备")
                .manufacturer("未知")
                .model("未知 (SOAP Fault响应)")
                .location("未知")
                .endpointReference("http://" + deviceAddress + "/onvif/device_service")
                .types("未知 (MatchingRuleNotSupported)")
                .scopes("未知")
                .xAddrs("http://" + deviceAddress + "/onvif/device_service")
                .discoveryTime(new Date())
                .onvifPort(80) // 默认端口
                .build();
                
            discoveredDevices.put(deviceAddress, device);
            log.info("已添加潜在ONVIF设备: {} (基于SOAP Fault响应)", deviceAddress);
            
        } catch (Exception e) {
            log.error("创建基本设备条目失败，设备地址: {}, 错误: {}", deviceAddress, e.getMessage());
        }
    }
}